/*
 * 网络通信模块
 *
 * 负责网络通信以及接收和处理网络请求
 *
 **/

#pragma once

#include "util.hh"
#include <httplib.h>
#include <easylog.h>
#include "config.hh"

namespace cloud
{
class server
{
public:
    using business = std::function<void(const httplib::Request&, httplib::Response&)>;

    static server& instance()
    {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
        static server svr(443);
#else
        static server svr(80);
#endif
        return svr;
    }

private:
    server(int port = config::instance().server_port())
        : _ip("0.0.0.0")
        , _port(port)
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
        , _svr(config::instance().sslcert_file().c_str(), 
               config::instance().sslkey_file().c_str())
#endif
    {}

    server(const server&) = delete;
    server& operator=(const server&) = delete;

public:
    void regist(business search, business record, business upload, business download, business filelist, business websvr)
    {
        _search = search;
        _record = record;
        _upload = upload;
        _download = download;
        _filelist = filelist;
        _websvr = websvr;
    }

    void run()
    {
        if (!_search)   throw except("search business is not callable");
        if (!_record)   throw except("record business is not callable");
        if (!_upload)   throw except("upload business is not callable");
        if (!_download) throw except("download business is not callable");
        if (!_filelist) throw except("filelist business is not callable");
        if (!_websvr)   throw except("filelist business is not callable");

        const std::string&   search_url = config::instance().search_prefix() + "/(.*)";
        const std::string&   record_url = config::instance().record_prefix();
        const std::string&   upload_url = config::instance().upload_prefix();
        const std::string& download_url = config::instance().download_prefix() + "/(.*)";
        const std::string& filelist_url = config::instance().filelist_prefix();

        _svr.Get (  search_url,   _search);
        _svr.Get (  record_url,   _record);
        _svr.Post(  upload_url,   _upload);
        _svr.Get (download_url, _download);
        _svr.Get (filelist_url, _filelist);
        _svr.Get ("/", _filelist);
        _svr.Get ("/(.*)", _websvr);

        easylog::info("http server started on {}", _port);

        if (!_svr.listen(_ip, _port))
            easylog::error("http server start failed on {}:{}", _ip, _port);
    }

private:
    std::string _ip;
    uint16_t _port;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
    httplib::SSLServer _svr;
#else
    httplib::Server _svr;
#endif

    business _search;
    business _record;
    business _upload;
    business _download;
    business _filelist;
    business _websvr;
};
}
